﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Reflection;
using System.ComponentModel;
using System.Collections.Generic;

namespace GoodStuff.Silverlight
{
    /// <remarks>
    /// Courtesy of Rob Eisenberg
    /// http://live.visitmix.com/MIX10/Sessions/EX15
    /// </remarks>    
    public class ReflectiveCommand : ICommand
    {
        private object _model;
        private MethodInfo _execute;
        private PropertyInfo _canExecute;

        public ReflectiveCommand(object model, string methodName)
        {
            _model = model;
            Type t = _model.GetType();
            _execute = t.GetMethod(methodName);            
            _canExecute = t.GetProperty("Can" + methodName);

            Setup();
        }

        public ReflectiveCommand(object model, MethodInfo execute, PropertyInfo canExecute)
        {
            _model = model;
            _execute = execute;
            _canExecute = canExecute;

            Setup();
        }

        private void Setup()
        {
            var notifier = _model as INotifyPropertyChanged;
            if (notifier != null && _canExecute != null)
            {
                notifier.PropertyChanged += (s, e) =>
                {
                    if (e.PropertyName == _canExecute.Name)
                    {
                        CanExecuteChanged(this, EventArgs.Empty);
                    }
                };
            }
        }

        public event EventHandler CanExecuteChanged = delegate { };

        public bool CanExecute(object parameter)
        {
            if (_canExecute != null)
            {
                return (bool)_canExecute.GetValue(_model, null);
            }
            return true;
        }       

        public void Execute(object parameter)
        {
            if (_execute != null)
            {
                object[] parameterList = null;
                if (_execute.GetParameters().Length > 0)
                {
                    parameterList = new object[] { parameter };
                }

                object returnValue = _execute.Invoke(_model, parameterList);
                if (returnValue != null)
                {
                    HandleReturnValue(returnValue);
                };
            }
        }

        private void HandleReturnValue(object returnValue)
        {
            //Make sure it is IEnumerable<Result>
            if (returnValue is IResult)
            {
                returnValue = new IResult[] { (IResult)returnValue };
            }

            if (returnValue is IEnumerable<IResult>)
            {
                new ResultEnumerator((IEnumerable<IResult>)returnValue).Enumerate();
            }
        }
    }
}
